#include "stdafx.h"
#include <MyControls/Frame.h>
#include <MyControls/App.h>
#include <MyControls/Constants.h>
#include <MyControls/Resource.h>
#include <MyControls/AsyncCall.h>
#include <mswin/file_dir.h>

namespace My {

BEGIN_MESSAGE_MAP(Frame, Frame::Base)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_CLOSE()
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	ON_MESSAGE(Message::Id, OnMessage)
	ON_WM_SETFOCUS()
	ON_COMMAND(ID_VIEW_RIGHT_PANELS, OnViewRightPanels)
	ON_UPDATE_COMMAND_UI(ID_VIEW_RIGHT_PANELS, OnUpdateViewRightPanels)
	ON_COMMAND(ID_VIEW_BOTTOM_PANELS, OnViewBottomPanels)
	ON_UPDATE_COMMAND_UI(ID_VIEW_BOTTOM_PANELS, OnUpdateViewBottomPanels)
END_MESSAGE_MAP()

static UINT ids[] =
{
	ID_SEPARATOR,           // status line indicator
};

Frame::Frame(Doc & doc) :
	m_Doc(doc),
	m_ToolBar(* this),
	m_RightBar(* this),
	m_BottomBar(* this),
	m_DisplayPanel(* this),
	m_RightSplitter(* this),
	m_BottomSplitter(* this),
	m_CornerGrip(* this),
	m_RightGrip(* this),
	m_BottomGrip(* this)
{
	m_Doc.Attach(this);

	m_RightSplit = 0;
	m_BottomSplit = 0;
	m_RightVisible = false;
	m_BottomVisible = false;
	m_RightAutoHide = false;
	m_BottomAutoHide = false;
	m_BottomFixedSize = false;

	m_Font.CreateFont(-11, 0, 0, 0, 400, FALSE, FALSE, 0, DEFAULT_CHARSET, 0, 0, 0, 0, "Tahoma");
	UpdateFont();

	bool rVisible = GetApp().GetProfileInt("Layout", "RightBarVisible", 1) != 0;
	bool bVisible = GetApp().GetProfileInt("Layout", "BottomBarVisible", 1) != 0;
	int	rSplit = (int) GetApp().GetProfileInt("Layout", "RightBarSize", 200);
	int	bSplit = (int) GetApp().GetProfileInt("Layout", "BottomBarSize", 200);

	SetSplit(rSplit, bSplit, rVisible, bVisible);
}

Frame::~Frame()
{
	m_Doc.Detach(this);

	GetApp().WriteProfileInt("Layout", "RightBarVisible", (int) m_RightBar.Visible());
	GetApp().WriteProfileInt("Layout", "BottomBarVisible", (int) m_BottomBar.Visible());
	GetApp().WriteProfileInt("Layout", "RightBarSize", m_RightSplit);
	GetApp().WriteProfileInt("Layout", "BottomBarSize", m_BottomSplit);
}

void Frame::PostNcDestroy()
{
//	delete this;
}

BOOL Frame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !Base::PreCreateWindow(cs) )
		return FALSE;

	cs.style = WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_MAXIMIZE|WS_CLIPCHILDREN;
	cs.dwExStyle &= ~WS_EX_CLIENTEDGE;

	return TRUE;
}

bool Frame::IsStatusBarVisible() const
{ 
	return m_StatusBar.m_hWnd != 0 
		&& m_StatusBar.GetStyle() & WS_VISIBLE; 
}

void Frame::SetSplit(int rs, int bs, bool rv, bool bv)
{
	if (m_hWnd != 0) 
	{
		CRect rClient = GetClientRect();
		
		if (IsStatusBarVisible())
			rClient.bottom -= StatusHeight;
		if (m_ToolBar.Visible())
			rClient.left += m_ToolBar.Width();

		if (rv && rs > rClient.Width() - MinViewSize)
			rs = rClient.Width() - MinViewSize;
		if (bv && bs > rClient.Height() - MinViewSize)
			bs = rClient.Height() - MinViewSize;

		CSize s = GetPreferredViewSize();
		s.cx += SplitterSize;
		s.cy += SplitterSize;

		if (abs(rs - rClient.Width() + s.cx) < 20)
			rs = rClient.Width() - s.cx;
		if (abs(bs - rClient.Height() + s.cy) < 20)
			bs = rClient.Height() - s.cy;
	}

	if (rs < Gap)
		rs = Gap;
	if (bs < Gap)
		bs = Gap;

	if (rs != 0 && rs < m_RightBar.GetMinWindowSize().cx)
		rs = m_RightBar.GetMinWindowSize().cx;
	int MinY = m_BottomBar.GetMinWindowSize().cy;
	if (bs != 0 && bs < MinY)
		bs = MinY;
	if (m_BottomFixedSize && bs > MinY)
		bs = MinY;

	if (rs != m_RightSplit || bs != m_BottomSplit
		|| rv != m_RightVisible || bv != m_BottomVisible) {

		m_RightSplit = rs;
		m_BottomSplit = bs;

		m_RightVisible = rv;
		m_BottomVisible = bv;

		RecalcLayout();
	}
}

void Frame::ToggleRightVisible()
{
	SetSplit(m_RightSplit, m_BottomSplit, !m_RightVisible, m_BottomVisible);
}

void Frame::ToggleBottomVisible() 
{
	SetSplit(m_RightSplit, m_BottomSplit, m_RightVisible, !m_BottomVisible);
}

void Frame::SetBottomFixedSize(bool Fixed)
{
	if (m_BottomFixedSize == Fixed)
		return;
	m_BottomFixedSize = Fixed;
	if (m_BottomFixedSize)
		SetSplit(m_RightSplit, m_BottomSplit, m_RightVisible, m_BottomVisible);
}

void Frame::UpdateTitle()
{
	String s;
	if (!m_Doc.IsEmpty()) 
	{
		if (m_Doc.GetFileName().empty())
			s = "(Untitled)";
		else
			s = mswin::basename(m_Doc.GetFileName());
		if (m_Doc.IsModified())
			s += " *";
		s += " - ";
	}
	s += GetApp().LoadString(MY_APP_TITLE);
	if (m_hWnd != 0)
		SetWindowText(s.c_str());
}

void Frame::ProcessEvent(Event & e)
{
	if (e.Is<CommandEventBase>())
		GetDoc().ProcessEvent(e);
	else
	if (e.Is<Doc::ActionsChange>())
		UpdateTitle();
	else
    if (e.Is<Doc::FileNameChange>())
		UpdateTitle();
	else
		Base::ProcessEvent(e);
}

CSize Frame::GetPreferredViewSize()
{
	return CSize(0, 0);
}

void Frame::RecalcLayout(BOOL bNotify) 
{
	Control::Invalidate();
	if (m_hWnd == 0)
		return;

	CRect r = GetClientRect();

	if (IsStatusBarVisible()) {
		m_StatusBar.SetWindowPos(NULL, r.left, r.bottom - StatusHeight, r.Width(), StatusHeight, SWP_SHOWWINDOW);
		r.bottom -= StatusHeight;
	}

	if (m_ToolBar.Visible())
		r.left += m_ToolBar.Width();
	if (m_RightBar.Visible())
		r.right -= m_RightSplit;
	r.right -= SplitterSize;
	if (m_BottomBar.Visible())
		r.bottom -= m_BottomSplit;
	r.bottom -= SplitterSize;

	r.bottom -= m_DisplayPanel.Height();

	if (GetView().m_hWnd != 0)
		GetView().SetWindowPos(NULL, r.left, r.top, r.Width(), r.Height(), SWP_SHOWWINDOW);

	m_ToolBar.UpdateBounds();

	m_RightBar.UpdateVisible();	
	if (m_RightBar.Visible())
		m_RightBar.UpdateBounds();	

	m_RightSplitter.UpdateBounds();

	m_BottomBar.UpdateVisible();
	if (m_BottomBar.Visible())
		m_BottomBar.UpdateBounds();

	m_DisplayPanel.UpdateBounds();

	m_BottomSplitter.UpdateBounds();

	UpdateWindow();
}

BOOL Frame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	if (nCode == CN_COMMAND) {
		CommandEvent event(nID);
		ProcessEvent(event);
		if (event.m_Handled)
			return TRUE;
	}
	else if (nCode == CN_UPDATE_COMMAND_UI) {
		UpdateCommandUIEvent event(nID, reinterpret_cast<CCmdUI *>(pExtra));
		ProcessEvent(event);
		if (event.m_Handled)
			return TRUE;
	}
	if (GetView().OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;
	return Base::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

int Frame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (Base::OnCreate(lpCreateStruct) == -1)
		return -1;
	if (!m_StatusBar.Create(this, WS_CHILD|WS_VISIBLE|CBRS_ALIGN_BOTTOM|CBRS_BORDER_TOP) || !m_StatusBar.SetIndicators(ids, sizeof(ids) / sizeof(UINT)))
		return -1;
	m_StatusBar.SetFont(&m_Font);
	bool StatusVisible = GetApp().GetProfileInt("Layout", "StatusBar", 1) != 0;
	if (!StatusVisible)
		m_StatusBar.ShowWindow(SW_HIDE);

	UpdateTitle();

	return 0;
}

void Frame::OnDestroy() 
{
	MSG msg;
	while (PeekMessage(&msg, m_hWnd, Message::Id, Message::Id, PM_REMOVE))
		delete reinterpret_cast<Message *>(msg.wParam);
	GetApp().WriteProfileInt("Layout", "StatusBar", (int) IsStatusBarVisible());
	Base::OnDestroy();
}

void Frame::OnClose()
{
	if (!m_Doc.IsEmpty()) {
		GetApp().OnCmdMsg(ID_FILE_CLOSE, 0, 0, 0);
		if (!m_Doc.IsEmpty())
			return;
	}
	Base::OnClose();
}

void Frame::OnSize(UINT nType, int cx, int cy) 
{
	Base::OnSize(nType, cx, cy);

	CRect rClient = GetClientRect();
	if (IsStatusBarVisible())
		rClient.bottom -= StatusHeight;
	if (m_ToolBar.Visible())
		rClient.left += m_ToolBar.Width();

	if (m_RightSplit > rClient.Width() - MinViewSize) {
		if (m_RightVisible) {
			m_RightVisible = false;
			m_RightAutoHide = true;
		}
	} else {
		if (!m_RightVisible && m_RightAutoHide) {
			m_RightVisible = true;
			m_RightAutoHide = false;
		}
	}
	if (m_BottomSplit > rClient.Height() - MinViewSize) {
		if (m_BottomVisible) {
			m_BottomVisible = false;
			m_BottomAutoHide = true;
		}
	} else {
		if (!m_BottomVisible && m_BottomAutoHide) {
			m_BottomVisible = true;
			m_BottomAutoHide = false;
		}
	}

	RecalcLayout();
}

BOOL Frame::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

LRESULT Frame::OnMessage(WPARAM w, LPARAM)
{
	std::auto_ptr<Message> msg(reinterpret_cast<Message*>(w));
	msg->Execute();
	return LRESULT(TRUE);
}

void Frame::OnSetFocus(CWnd* pOldWnd)
{
	if (m_pFocusControl == 0)
		SetFocusControl(this);
}

void Frame::HandleFocus()
{
	if (GetView().m_hWnd != 0)
		GetView().SetFocus();
}

void Frame::OnViewRightPanels() 
{
	ToggleRightVisible();
}

void Frame::OnUpdateViewRightPanels(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(GetRightBar().Visible() ? 1 : 0);
}

void Frame::OnViewBottomPanels() 
{
	ToggleBottomVisible();
}

void Frame::OnUpdateViewBottomPanels(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(GetBottomBar().Visible() ? 1 : 0);
}

} // My